package net.xmmpp.uc.im.gateway.filter;

//import org.apache.commons.lang.StringUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class ResponseLogFilter implements GlobalFilter, Ordered {

    private static final Logger LOGGER = LoggerFactory.getLogger(ResponseLogFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        try {
            ServerHttpResponse originalResponse = exchange.getResponse();
            DataBufferFactory bufferFactory = originalResponse.bufferFactory();

            HttpStatus statusCode = originalResponse.getStatusCode();

//            StringBuilder strBuilder = new StringBuilder();
//            strBuilder.append("Response start at: ").append(LocalDateTime.now()).append('\n')
//                    .append("Response url: ").append(requestUrl).append('\n')
//                    .append("Response method: ").append(method).append('\n')
//                    .append("Response headers: ").append('\n');

            if (statusCode == HttpStatus.OK) {
                ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
                    @Override
                    public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                        //log.info("body instanceof Flux: {}", (body instanceof Flux));
                        if (body instanceof Flux) {
                            Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                            //
                            return super.writeWith(fluxBody.map(dataBuffer -> {
                                byte[] content = new byte[dataBuffer.readableByteCount()];
                                dataBuffer.read(content);
                                DataBufferUtils.release(dataBuffer);//释放掉内存
                                // 构建日志
                                StringBuilder responseLog = printHeader(exchange, chain);
                                String data = new String(content, StandardCharsets.UTF_8);//data

                                responseLog.append("Response Body: ").append('\n')
                                        .append(data).append('\n')
                                        .append("================  Gateway Response End  =================\n");

                                LOGGER.info(responseLog.toString());

                                return bufferFactory.wrap(content);
                            }));
                        } else {
                            LOGGER.error("<--- {} 响应code异常", getStatusCode());
                        }
                        return super.writeWith(body);
                    }
                };

                return chain.filter(exchange.mutate().response(decoratedResponse).build());
            }

            return chain.filter(exchange);//降级处理返回数据
        } catch (Exception e) {
            LOGGER.error("gateway log exception.\n" + e);
            return chain.filter(exchange);
        }
    }

    private StringBuilder printHeader(ServerWebExchange exchange, GatewayFilterChain chain){
        // 构建成一条长日志
        StringBuilder responseLog = new StringBuilder(200);
        // 日志参数
        List<Object> responseArgs = new ArrayList<>();
        responseLog.append("\n\n================ Gateway Response Start  ================\n");
        ServerHttpResponse response = exchange.getResponse();
        // 参数
        String requestMethod = exchange.getRequest().getMethodValue();
        String path = exchange.getRequest().getPath().pathWithinApplication().value();
        MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
        String requestUrl = UriComponentsBuilder.fromPath(path).queryParams(queryParams).build().toUriString();

        responseLog.append("Response start at: ").append(LocalDateTime.now()).append('\n')
        .append("Response url: ").append(requestUrl).append('\n')
        .append("Response method: ").append(requestMethod).append('\n')
        .append("Response Status Code: ").append(response.getStatusCode().value()).append('\n')
        .append("Response headers: ").append('\n');

        // 打印请求头
        HttpHeaders headers = response.getHeaders();
        headers.forEach((headerName, headerValue) -> {
            responseArgs.add(headerName);
            responseLog.append('\t').append(headerName).append(": ").append(headerValue).append('\n');

        });

        return responseLog;
    }

    public Mono<Void> logHeader(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        // 打印请求路径
        String path = request.getPath().pathWithinApplication().value();

        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    MultiValueMap<String, String> queryParams = request.getQueryParams();
                    String requestUrl = UriComponentsBuilder.fromPath(path).queryParams(queryParams).build().toUriString();

                    // 构建成一条长日志
                    StringBuilder responseLog = new StringBuilder(200);
                    // 日志参数
                    List<Object> responseArgs = new ArrayList<>();
                    responseLog.append("\n\n================ Gateway Response Start  ================\n");
                    ServerHttpResponse response = exchange.getResponse();
                    // 状态码个path占位符: 200 get: /xxx/xxx/xxx?a=b
                    responseLog.append("<=== {} {}: {}\n");
                    // 参数
                    String requestMethod = request.getMethodValue();
                    responseArgs.add(response.getStatusCode().value());
                    responseArgs.add(requestMethod);
                    responseArgs.add(requestUrl);

                    // 打印请求头
                    HttpHeaders headers = response.getHeaders();
                    headers.forEach((headerName, headerValue) -> {
                        responseLog.append("===Headers===  {}: {}\n");
                        responseArgs.add(headerName);
//                        responseArgs.add(StringUtils.join(headerValue.toArray()));
                    });

                    responseLog.append("================  Gateway Response End  =================\n");
                    // 打印执行时间
                    LOGGER.info(responseLog.toString(), responseArgs.toArray());
                })
        );
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
